package com.gitee.openviducn.inspector.cdr.repository;

import com.gitee.openviducn.inspector.domain.vo.request.WebhookCDRRequest;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Author: https://gitee.com/wesleyOne
 * @Date: 04.19 2020
 */
@Slf4j
@Component
public class InMemoryCDRRepository implements BaseCDRRepository {

    private static final long MAX_CDR_LIVE_TIME_MS = 1000 * 60 * 5;
    private static final long MAX_CDR_LIVE_SIZE = 1000;

    /**
     * {@code sessionId -> event -> cdr list}
     */
    private Map<String, Cache<String, List<WebhookCDRRequest>>> allSessionCDR = new ConcurrentHashMap<>();


    @Override
    public void save(WebhookCDRRequest cdr) {
        List<WebhookCDRRequest> cdrRequestList = allSessionCDR.computeIfAbsent(cdr.getSessionId(), e -> Caffeine.newBuilder()
                .maximumSize(MAX_CDR_LIVE_SIZE)
                .expireAfterWrite(MAX_CDR_LIVE_TIME_MS, TimeUnit.MILLISECONDS)
                .build())
                .getIfPresent(cdr.getEvent());
        if(CollectionUtils.isEmpty(cdrRequestList)) {
            cdrRequestList = Lists.newLinkedList();
            allSessionCDR.get(cdr.getSessionId()).put(cdr.getEvent(), cdrRequestList);
        }
        cdrRequestList.add(cdr);
    }

    @Override
    public List<WebhookCDRRequest> queryBySessionIdAndEventsBetween(String sessionId, Set<String> events) {
        if (!allSessionCDR.containsKey(sessionId)) {
            return Lists.newArrayList();
        }
        Cache<String, List<WebhookCDRRequest>> eventCache = allSessionCDR.get(sessionId);
        Map<String, List<WebhookCDRRequest>> allPresent = eventCache.getAllPresent(events);
        if (allPresent.size() <= 0) {
            return Lists.newArrayList();
        }
        List<WebhookCDRRequest> cdrList =  Lists.newArrayList();
        allPresent.keySet().stream().filter(events::contains).forEach(event -> cdrList.addAll(allPresent.get(event)));
        cdrList.sort((o1, o2) -> (o1.getTimestamp() <= o2.getTimestamp()) ? 1 : -1);
        return cdrList;
    }
}
